package io.wongxd.demo.widget

import androidx.compose.animation.core.InfiniteRepeatableSpec
import androidx.compose.animation.core.RepeatMode
import androidx.compose.animation.core.animateFloat
import androidx.compose.animation.core.rememberInfiniteTransition
import androidx.compose.animation.core.tween
import androidx.compose.foundation.Canvas
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.size
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.blur
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.withContext
import kotlin.math.absoluteValue
import kotlin.math.sqrt


@Composable
fun NeonLamp(modifier: Modifier, progress: Int) {

    val bgColor = Color.White

    val infiniteTransition = rememberInfiniteTransition(label = "")
    val circleSize by infiniteTransition.animateFloat(
        30f, 40f,
        label = "",
        animationSpec = InfiniteRepeatableSpec(tween(1500), repeatMode = RepeatMode.Reverse)
    )

    var screenW by remember { mutableStateOf(0f) }
    var screenH by remember { mutableStateOf(0f) }
    val gridCount = 100
    val xUnit = screenW / gridCount
    val yUnit = screenH / gridCount
    // 像素点的半径
    val pointRadius = xUnit.coerceAtMost(yUnit) / 2
    val xList = Array(gridCount) { xUnit + it * xUnit }
    val yList = Array(gridCount) { xUnit + it * xUnit }

    Canvas(modifier = modifier.blur(3.dp),
        onDraw = {
            screenW = this.size.width
            screenH = this.size.height

            for (xIndex in xList.indices) {
                for (yIndex in yList.indices) {
                    val xDis = (xList[xIndex] - center.x).absoluteValue
                    val yDis = (yList[yIndex] - center.y).absoluteValue
                    val disFromCenter = sqrt(xDis * xDis + yDis * yDis).toInt()
                    // 将所有的点与画布中心距离 disFromCenter 除上circleSize,
                    // 除出来得到的值如果不超过9就去绘制点，这就相当于把整个绘制范围分成了十份
                    val div = disFromCenter / circleSize
                    if (div <= 9) {
                        // 缩小比例, 每一份的透明度与半径缩小比例
                        val alphaRate = (div + 1) / 10
                        drawCircle(
                            bgColor,
                            // 将半径乘上的比例以及透明度变成1-radio,并且把半径增大一倍，为的就是去掉圆点之间的空隙
                            radius = pointRadius * 2 * (1 - alphaRate),
                            center = Offset(xList[xIndex], yList[yIndex]),
                            alpha = 1 - alphaRate
                        )
                    }
                }
            }
        })
}


// 定义一个GridPoint类来表示点阵中的点
private class GridPoint(val x: Int, val y: Int)

private val ledGridMap = mapOf(
    "0" to listOf(
        GridPoint(3, 0),
        GridPoint(4, 0),
    ),
    "1" to listOf(
        GridPoint(3, 1),
        GridPoint(4, 0),
        GridPoint(4, 1),
        GridPoint(4, 2),
        GridPoint(4, 3),
        GridPoint(4, 4),
        GridPoint(4, 5),
        GridPoint(4, 6),
        GridPoint(4, 7),
        GridPoint(3, 7),
        GridPoint(5, 7),
    ),
    "2" to listOf(
        GridPoint(3, 1),
        GridPoint(4, 0),
    ),
    "3" to listOf(
        GridPoint(3, 1),
        GridPoint(4, 0),
    ),
    "4" to listOf(
        GridPoint(3, 1),
        GridPoint(4, 0),
    ),
    "5" to listOf(
        GridPoint(3, 1),
        GridPoint(4, 0),
    ),
    "6" to listOf(
        GridPoint(3, 1),
        GridPoint(4, 0),
    ),
    "7" to listOf(
        GridPoint(3, 1),
        GridPoint(4, 0),
    ),
    "8" to listOf(
        GridPoint(3, 1),
        GridPoint(4, 0),
    ),
    "9" to listOf(
        GridPoint(3, 1),
        GridPoint(4, 0),
    )
)

@Composable
fun Led(modifier: Modifier, str: String, txtColor: Color) {

    var screenW by remember { mutableStateOf(0f) }
    var screenH by remember { mutableStateOf(0f) }
    val gridCount = 8
    val xUnit = screenW / gridCount
    val yUnit = screenH / gridCount

    val xList = Array(gridCount) { xUnit + it * xUnit }
    val yList = Array(gridCount) { xUnit + it * xUnit }

    val points = ledGridMap[str] ?: return

    Canvas(modifier = modifier,
        onDraw = {
            screenW = this.size.width
            screenH = this.size.height

            // bg
            for (x in xList) {
                for (y in yList) {
                    drawRect(
                        Color.Green,
                        topLeft = Offset(x - xUnit * .9f, y - yUnit * .9f),
                        size = Size(xUnit * .8f, yUnit * .8f)
                    )
                }
            }

            for (point in points) {
                drawRect(
                    txtColor,
                    topLeft = Offset(xList[point.x] - xUnit * .9f, yList[point.y] - yUnit * .9f),
                    size = Size(xUnit * .8f, yUnit * .8f)
                )
            }
        }
    )

}

@Preview(showBackground = true, backgroundColor = 0xffffffff)
@Composable
private fun RenderPreView() {
    Box(
        modifier = Modifier
            .size(220.dp)
            .background(Color.Black)
    ) {
        var pb by mutableStateOf(0)
        LaunchedEffect(key1 = Unit, block = {
            withContext(Dispatchers.IO) {
                while (true) {
                    delay(200)
                    if (pb == 100) pb = 0 else pb += 1
                }
            }
        })
        NeonLamp(Modifier.fillMaxSize(), pb)

        Box(
            modifier = Modifier
                .align(Alignment.Center)
                .size(50.dp)
                .background(Color.Black)
        ) {
            Led(modifier = Modifier.fillMaxSize(), str = "1", txtColor = Color.White)
        }
    }
}